BEFORE
, you can prepend content.DokuWiki users can create and trigger their own events and they can register to be notified of events triggered by DokuWiki. This documentation looks at how to use and write handlers for the events which are triggered by DokuWiki and are described in the DokuWiki events list.
To begin with, it's helpful to understand how events are processed. To be notified of an event, your code must register to receive the notification. Registering places your request for notification on a list of requests for the event. The list is a first-come, first-served array; that is, it's treated as a stack where each next request is pushed on the end of the list. This means it's possible to implement more than one handler for the same event. When more handlers are registered, these will have a unknown, random order.
When DokuWiki processes an action that has an associated event, it does not perform this action immediately. Instead, it triggers an event for this action. For instance, when DokuWiki goes to write a wiki page, it triggers an IO_WIKIPAGE_WRITE event, which initiates the event notification process.
There are actually two lists: one for before and one for after DokuWiki performs its own action. These are designated by the BEFORE
and AFTER
keywords, used when registering for an event. Before processing its own action, DokuWiki loops through all the BEFORE
requests, making its own action the last to be processed. This gives your code the opportunity to act on this event before DokuWiki gets to it. In the case of IO_WIKIPAGE_WRITE, for instance, you can make changes to the page content before it gets sent to the browser.
After performing its own action, DokuWiki loops through all the AFTER
requests. In the case of the TPL_ACT_RENDER event, for instance, it's possible to append content to the wiki page.1)
DokuWiki's action is the default. But during the BEFORE
phase of some events, it's also possible to stop the default from taking place. Similarly, an event handler can short-circuit the event loop and prevent any handlers remaining on the stack from being executed.
In simplified pseudo code, the event process would look like this:
var $process_event = true; var $default_stopped = false; loop_through_BEFORE_List() { return if $process_event == false; } do_DokuWiki_Action() { return if $default_stopped; } var $process_event = true; loop_through_AFTER_List(){ return if $process_event == false; }
Event handlers are registered using the register_hook() function of the EventHandler class, the specifications for which are found on Dokuwiki's events page.
The function definition for register_hook()
is as follows:
void register_hook(string $event, string $advise, object $obj, string $method, mixed $param = null, int $seq = 0)
$event
is the name of the event, for instance IO_WIKIPAGE_WRITE $advise
is either BEFORE
or AFTER
$obj
is either a reference, which in a plugin would be the $this
variable, or else it is NULL, in which case the callback function must be in the global scope$method
is the name of the callback function which will handle the event$param
is an optional container for any data which the callback might require$seq
is an optional sequence number used to control the order in which hooks are executed (since release 2014-05-05 ”Ponder Stibbons”).
To call register_hook()
from the global scope, you set $obj
to null and use
the global variable $EVENT_HANDLER:
$EVENT_HANDLER->register_hook( ... )
$EVENT_HANDLER
is a reference to dokuwiki\Extension\EventHandler
. It controls the execution of all events, both user-defined and DokuWiki-defined.
Action plugins do not need direct access to the global $EVENT_HANDLER
. They are specifically designed for adding handles to DokuWiki events, and typically you would be calling register_hook()
from an action plugin.
In action plugins, event handlers are registered in the register()
method, which all action plugins must implement. It takes one parameter, $controller
, which is in effect an alias for $EVENT_HANDLER
and which is used to register event handlers:
use dokuwiki\Extension\EventHandler; ... public function register(EventHandler $controller) { $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'templateRender'); }
inc/template.php
by the function which dispatches the page to be formatted and printed.templateRender()
, which will be found in the plugin object.$this
parameter, which points to the plugin object, will give DokuWiki's event module access to the handler.The handler has this basic form:
use dokuwiki\Extension\Event; ... /** * @param Event $event the Event object * @param mixed $param value provided as fifth argument to register_hook() */ public function handler (Event $event, $param) { // handler code }
When EventHandler calls the handler function, it passes in two parameters, the current $event
object and $param
. which is designed to hold any additional data relevant to the event. $param
is the $param
that is passed through as the fifth parameter in register_hook().
2)
The authoritative specification for the event object Event is found on the event page and should be consulted.
The $event
object has six fields:
name
: Event Name;data
: Specific to each event, data may include, page content, headers, meta data, objects, the current action (e.g. edit, index), whatever is needed of for the execution of the event; it may also hold no data, and it has no fixed structure: it may be a string, array, multidimensional array, object.result
: First it holds the return value from the default handler, which can then be consulted by an AFTER
handler. It can then be modified by an AFTER
handler, in which case it might be information for any subsequent AFTER
handlers. Ultimately, it will be returned to the Event::createAndTrigger() function. In most case this value is either true
, if the default action has taken place, or null
if it hasn't.canPreventDefault
: true
or false
, indicating whether or not the default action for this event can be stopped; this information is available from DokuWiki's events list.runDefault
: true
or false
, indicating whether the default action for this event should be enabled; its default value is true but can be set to false by calling $event->preventDefault()
.mayContinue
: This value defaults to true
. If $event->stopPropagation()
is called, it is set to false, stopping any further processing of the event BEFORE
or AFTER
handlers registered for this event, but this function does not prevent the default action taking place.$event->preventDefault()
BEFORE
handler prevents the default action taking from place; it has no effect if called from an AFTER
handler. It sets $event->runDefault
to false
. Being able to prevent the default action has considerable utility. It can stop a page from being cached when used with the PARSER_CACHE_USE event. It can also prevent a page from being sent to the browser at various stages of the rendering and output process, each of which is represented by an event. One enticing idea is preventing the TPL_ACT_UNKNOWN default to set up your own action in response to an unrecognized action request. However, this idea would not work because it is blocked the by action_clean()
method in inc/action.php. See the events list on the DokuWiki site for details and possibilities.$event->stopPropagation()
. $event->mayContinue
to false
and stops any further processing of the event by event handlers; it does not prevent the default action taking place. It comes into play where you have set more than one handler for the same event. If you have registered an event for both BEFORE
and AFTER
execution, canceling the BEFORE
does not stop propagation of the AFTER
events. (See the above section on the Event Loop).$name
: This is the name of the event. If you implement your own event, then this is the name of that event.$data
: Whatever is required for your data$action
: This is the default action, most probably a function in the global scope.$canPreventDefault
: true
or false
, to indicate whether or not the default action can be stopped. In user-defined events, this can be left at the default value of true
.$event->result
.$action
parameter of Event::createAndTrigger()
.See event handlers code samples.